﻿// 
//	Main file of project (Lab 3)
//	© Denis Kajgorodov
//

#include <iostream>
#include <string>
#include <fstream>
#include <conio.h>
#include <windows.h>
#include <windowsx.h>
#include <iomanip>
#include <cctype>
#include <process.h>
#include "Trapeze.h"
#include "MyWindow.h"
#include "HashTable.h"

using namespace std;

// Global variables
HINSTANCE hInstance; 
HINSTANCE hPrevInst; 
LPSTR lpszArgs; 
int nWinMode;
MyWindow newWindow;

// Keyboard values
const unsigned char ESCAPE = 27;
const unsigned char SPACE = 32;
const unsigned char UP_ARROW = 72;
const unsigned char LEFT_ARROW = 75;
const unsigned char DOWN_ARROW = 80;
const unsigned char RIGHT_ARROW = 77;
const unsigned char KEY_ONE = 49;
const unsigned char KEY_TWO = 50;
const unsigned char KEY_THREE = 51;

// Message loop
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
{
	switch(message) 
	{                                   
	case WM_DESTROY:                     
		PostQuitMessage (0);                      
		break; 
	default:                                 				
		return DefWindowProc (hwnd,message,wParam,lParam);
	}                                                          
	return 0;
}

// Start new thread for creating of window
void newThread(void *)
{ 
	newWindow.WinMain(hInstance,  hPrevInst, lpszArgs,  nWinMode);  
}

bool readParametres (string filename, Trapeze& figure, Trapeze& figureInside)
{
	fstream stream(filename);				
	POINT points[N];						
	for (char i = 0; i < N; i++)			
	{
		stream >> points[i].x;
		stream >> points[i].y;
	}
	figure.setPoints(points);
	int width_style;
	stream >> width_style;
	figure.setWidth(width_style);
	stream >> width_style;
	figure.setStyle(width_style);
	int Red, Green, Blue;
	stream >> Red >> Green >> Blue;
	figure.setLineColor(RGB(Red, Green, Blue));
	stream >> Red >> Green >> Blue;
	figure.setFloodColor(RGB(Red, Green, Blue));
	for (char i = 0; i < N; i++)
	{
		stream >> points[i].x;
		stream >> points[i].y;
	}
	figureInside.setPoints(points);
	stream >> width_style;
	figureInside.setWidth(width_style);
	stream >> width_style;
	figureInside.setStyle(width_style);
	stream >> Red >> Green >> Blue;
	figureInside.setLineColor(RGB(Red, Green, Blue));
	stream >> Red >> Green >> Blue;
	figureInside.setFloodColor(RGB(Red, Green, Blue));
	stream.close();
	return true;
}

inline void displayMenu ()
{
	cout << setw(15) << "- MENU -" << endl;
	cout << "Commands for figure relocation:" << endl;
	cout << setw(13) << "[ARROW UP]" << endl;
	cout << setw(15) << "[ARROW DOWN]" << endl;
	cout << setw(15) << "[ARROW LEFT]" << endl;
	cout << setw(16) << "[ARROW RIGHT]" << endl;
	cout << "[KEY ONE]" << "- Add a figure inside" << endl;
	cout << "[KEY TWO]" << "- Change line color" << endl;
	cout << "[KEY THREE]" << "- Change flood color" << endl;
	cout << "[SPACE]" << "- Show menu" << endl;
	cout << "[ESC]" << "- Exit" << endl << endl;
}

bool isInside (POINT figureOut[], POINT point)
{
	POINT vector[4] = {figureOut[1], figureOut[2], figureOut[3], figureOut[0]};
	POINT vPoint[4] = {point, point, point, point};
	for (short int i = 0; i < N; i++)
	{
		vector[i].x -= figureOut[i].x;
		vector[i].y -= figureOut[i].y;
		vPoint[i].x -= figureOut[i].x;
		vPoint[i].y -= figureOut[i].y;
	}
	for (short int i = 0; i < N; i++)
	{
		int mult = (vector[i].x*vPoint[i].y - vector[i].y*vPoint[i].x);
		if (mult < 0) return false;;
	}
	return true;
}

void readFile (string filename, HashTable* myHashTable)
{
	fstream stream(filename);				
	POINT points[N];
	Trapeze* figure = nullptr;
	Trapeze* figureInside = nullptr;
	for (char i = 0; i < N; i++)			
	{
		stream >> points[i].x;
		stream >> points[i].y;
	}
	(*figure).setPoints(points);
	int width_style;
	stream >> width_style;
	(*figure).setWidth(width_style);
	stream >> width_style;
	(*figure).setStyle(width_style);
	int Red, Green, Blue;
	stream >> Red >> Green >> Blue;
	(*figure).setLineColor(RGB(Red, Green, Blue));
	stream >> Red >> Green >> Blue;
	(*figure).setFloodColor(RGB(Red, Green, Blue));
	for (char i = 0; i < N; i++)
	{
		stream >> points[i].x;
		stream >> points[i].y;
	}
	(*figureInside).setPoints(points);
	stream >> width_style;
	(*figureInside).setWidth(width_style);
	stream >> width_style;
	(*figureInside).setStyle(width_style);
	stream >> Red >> Green >> Blue;
	(*figureInside).setLineColor(RGB(Red, Green, Blue));
	stream >> Red >> Green >> Blue;
	(*figureInside).setFloodColor(RGB(Red, Green, Blue));
	stream.close();
	(*myHashTable).Add(*figure);
	(*myHashTable).Add(*figureInside);
}

int main()
{
	_beginthread(newThread, 0, NULL);
	Sleep(100);
	HWND myHWND = newWindow.hwnd; 
	HDC myHDC = GetDC(myHWND); 
	cout << myHWND << endl;			//! Checking HWND
	string filename = "input.txt";
	Trapeze Figure;
	Trapeze FigureInside;
	readParametres(filename, Figure, FigureInside);

	// New
	//HashTable* myHashTable = new HashTable();
	//readFile(filename, myHashTable);

	SetBkColor(myHDC, RGB(0, 0, 0));
	HPEN firstPen = CreatePen (Figure.getStyle(), Figure.getWidth(), Figure.getLineColor());
	HPEN secondPen = SelectPen(myHDC, firstPen);
	HBRUSH mainBrush = CreateSolidBrush(Figure.getFloodColor()); 
	unsigned int key = 0;
	displayMenu();
	HBRUSH secondBrush = CreateSolidBrush(FigureInside.getFloodColor());
	do
	{
		int R, G, B;
		SelectBrush(myHDC, mainBrush); 
		InvalidateRect(myHWND, 0, true);
		UpdateWindow(myHWND);
		Figure.drawFigure(myHWND, myHDC);
		try
		{
			switch (key)
			{
			case LEFT_ARROW:
				Figure.moveLeft(myHWND, myHDC);
				FigureInside.moveLeft(myHWND, myHDC);
				break;
			case UP_ARROW:
				Figure.moveUp(myHWND, myHDC);
				FigureInside.moveUp(myHWND, myHDC);
				break;
			case DOWN_ARROW:
				Figure.moveDown(myHWND, myHDC);
				FigureInside.moveDown(myHWND, myHDC);
				break;
			case RIGHT_ARROW:
				Figure.moveRight(myHWND, myHDC);
				FigureInside.moveRight(myHWND, myHDC);
				break;
			case SPACE:
				displayMenu();
				break;
			case KEY_ONE:
				POINT outPoints[N];
				POINT inPoints[N];
				FigureInside.getPoints(outPoints);
				Figure.getPoints(inPoints);
				for (char i = 0; i < N; i++)
					if (isInside(outPoints, inPoints[i]))
						throw NotInside;
				SelectBrush(myHDC, secondBrush); 
				FigureInside.drawFigure(myHWND, myHDC);
				break;

			case KEY_TWO:
				cout << "Enter new line color in RGB format: ";
				cin >> R >> G >> B;
				cin.clear();	
				cin.ignore(cin.rdbuf()->in_avail());
				cout << "R = " << R << "   G = " << G << "   B = " << B << endl;
				if (R < 0 || R > 255 || G < 0 || G > 255 || B < 0 || B > 255)
					throw IncorrectData;		
				Figure.setLineColor(RGB(R, G, B));
				firstPen = CreatePen (Figure.getStyle(), Figure.getWidth(), Figure.getLineColor());
				secondPen = SelectPen(myHDC, firstPen);
				cout << "Line color was changed." << endl;
				break;

			case KEY_THREE:
				cout << "Enter new flood color in RGB format: ";
				cin >> R >> G >> B;
				cin.clear();	
				cin.ignore(cin.rdbuf()->in_avail());
				if (R < 0 || R > 255 || G < 0 || G > 255 || B < 0 || B > 255)
					throw IncorrectData;
				Figure.setFloodColor(RGB(R, G, B));
				mainBrush = CreateSolidBrush(Figure.getFloodColor()); 
				cout << "Flood color was changed." << endl;
				break;
			default:
				break;
			}
		}
		catch (Exceptions error)
		{
			switch (error)
			{
			case NotVisible:
				MessageBoxA(NULL, "Figure will not visible.", "Warning", MB_OK);
				break;
			case NotTrapeze:
				MessageBox(NULL, "Figure isn't trapeze.", "Warning", MB_OK);
				break;
			case NotInside:
				MessageBox(NULL, "Second figure is not inside.", "Warning", MB_OK);
				break;
			case IncorrectData:
				cout << "Incorrect data" << endl;
				break;
			default:
				break;
			}
		}
	}
	while ((key = _getch()) != ESCAPE);
	DeletePen(firstPen);  
	ReleaseDC(myHWND, myHDC);
	cout << "The program will closed.";
	Sleep(500);
	return 0;
}
/* Степень выражения качества или степень качественной характеристики - давайте так лучше скажем

	Количественная характеристика измеряема
	чуть ниже фразу 
	любая вещь представлена единством количественной и качественной характеристики
	тоже ребят на примере надо посмотреть
	для тебя какое-то значение имеет
	и так далее
	значит договорились
	это любая вещь
	так, теперь дальше
	давайте третий пункт - понятие меры
	Мера это  такое единство количественных и качественных характеристик вещи, еднство подчеркнуть!!
	в пределах которого вещь является таковой.
	Опять же, в твоих руках ручка
	Если теперь, ребята, начать изменять количественную характеристику, у тебя 
	мы вышли за пределы!!!!
	Ну и я рассказывал уже, ребята
	ребята ребята ребята ребята ребята ребята 
*/